package main

import (
	"awesomeProject/chapter1/mysql"
	"awesomeProject/chapter1/redis"
	"awesomeProject/chapter1/web"
	"database/sql"
	"fmt"
	"github.com/gin-gonic/gin"
	"log"
	"net/http"
)

/**go语言竟然可以导入包，然后用包名访问方法*/
func main() {
	//testMysql()
	//testRedis()

	//startWeb()
	//test()
	//testModify()
	//deferTest()
	//test2()
	//web.StartWeb()
	web.StartWeb3()
}

/**通道使用*/
func test2() {
	s := []int{7, 2, 8, -9, 4, 0}
	c := make(chan int) //创建一个通道
	go sum(s[:len(s)/2], c)
	go sum(s[len(s)/2:], c)
	x, y := <-c, <-c
	fmt.Println(x, y) // 从通道 c 中接收
}

func sum(s []int, c chan int) {
	sum := 0
	for _, v := range s {
		sum += v
	}
	c <- sum // 把 sum 发送到通道 c
}

/*
在循环中，依次定义了四个 defe r代码块。结合规则一，我们可以明确得知每个defer代码块应该输出什么值。
*先进后出的原则，我们可以看到依次输出了3210，类似java中的栈
*/
func deferTest() {
	for i := 0; i < 4; i++ {
		defer fmt.Print(i)
	}

}

func testModify() {
	x := 5
	modifyInt(x)
	fmt.Println(x) // 输出: 5

	slice := []int{1, 2, 3}
	modifySlice(slice)
	fmt.Println(slice) // 输出: [100 2 3]
}

func modifyInt(x int) {
	x = 100 // 修改的是x的副本，对原始变量没有影响
}

func modifySlice(s []int) {
	s[0] = 100 // 修改的是切片引用的底层数组的元素，会影响到原始切片
}
func test() {
	//s := sql.NullString{String: "111"}
	//结构体定义

	f := mysql.Fiction{
		ID:   1,
		Name: "haha",
		Auth: sql.NullString{String: "赵信", Valid: true}, // 注意这里如何初始化sql.NullString
	}
	f2 := mysql.Fiction{2, "盖伦", sql.NullString{String: "haha", Valid: true}}

	//结构体返回指针
	f3 := &mysql.Fiction{3, "皇子", sql.NullString{String: "haha", Valid: true}}
	//go通过包名来调用方法，被调用的方法需要大写，在类里面调用只需要小写
	//值传递和引用传递都可以，通过&f 也可以取到对象的值
	mysql.TestFiction(f)    //haha
	mysql.TestFiction2(&f2) //盖伦
	mysql.TestFiction2(&f)  //盖伦

	fmt.Println("----------------------------")
	f.Name = "lili"
	mysql.TestFiction(f)   //lili
	mysql.TestFiction2(&f) //lili
	mysql.TestFiction2(f3) //皇子

	mysql.TestFiction3(f3)
	fmt.Println(f3.Name) //蚂蚱，传了地址进去，值改了

	mysql.TestFiction4(f)
	fmt.Println(f.Name) //lili ,上面的值，传递进去的结构体，是副本，值没有变
}

/**创建web服务*/
func startWeb() {
	/**使用的是gin的Default()函数来创建一个默认的gin实例。r.GET()是为了注册get请求路由，而r.Run()函数是为了启动服务。*/
	r := gin.Default()

	//get传参
	r.GET("/myget", func(c *gin.Context) {
		var req web.MyGETRequest
		if err := c.ShouldBindQuery(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		res := web.MyResponse{Message: "hello" + req.Name}
		c.JSON(http.StatusOK, res)
	})

	//post json传参
	r.POST("/hello", func(c *gin.Context) {
		var req web.MyRequest
		if err := c.ShouldBindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		res := web.MyResponse{Message: "hello" + req.Name} //还得大写才能用req.Name
		c.JSON(http.StatusOK, res)
	})
	r.Run("localhost:8093")
}

func testMysql() {
	db, err := mysql.Connect()
	if err != nil {
		log.Print(err)
	}

	//查询
	//datas, err := mysql.QueryData(db)
	//fmt.Println(len(datas))
	//for i := 0; i < len(datas); i++ {
	//	data := datas[i]
	//	fmt.Println(data.Name)
	//}

	//单个查询
	//data, err := mysql.SelectById(db, 30)
	//fmt.Println(data)
	//mysql.CloseDB(db)

	//插入
	//name := "诸葛亮斗王朗"
	//page := 1000
	//data, err := mysql.InsertData(db, name, page)
	//fmt.Println(data)
	//mysql.CloseDB(db)
	//
	//fmt.Println("插入成功")
	//time.Sleep(10 * time.Second)

	//更新数据
	//mysql.UpdateData(db, "魔女的交换", 2)
	//mysql.CloseDB(db)

	//删除数据
	//mysql.DeleteData(db, name)
	//mysql.CloseDB(db)

	//分页查询
	pageNum := 10 //页数量
	pageSize := 1 //页码
	dataList, err := mysql.PageQuery(db, pageNum, pageSize)
	for i := 0; i < len(dataList); i++ {
		data := dataList[i]
		fmt.Println(data.Name)
	}
}

/*
上面的mysql connect根本就不需要返回db，创建一个类的全局变量，在该类下使用就有了，但如果是跨类、跨包，不然会db对象，还能查？
*/
func testRedis() {
	//rdb, err := redis.InitRedisClient()
	err := redis.InitRedisClient()
	if err != nil {
		fmt.Println(err)
	}
	//fmt.Println(rdb)

	redis.RedisSetKey("haha1", "hello")
	key, err := redis.RedisGetKey("haha1")
	fmt.Println(key)
}
